package model

import (
	"fmt"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

// 用户模型
type User struct {
	gorm.Model
	Username string
	Password string
	Nickname string
	Avatar   string
	Email    string
	DeviceId string
	Role     string
	State    int8
}

//用户签到模型
type UserDaka struct {
	gorm.Model
	Uid       string
	Data      string `gorm:"type:date;not null"`
	Integral  int
	IsUseCode int //是否使用积分签到 1是 0否
}

const (
	// 密码加密级别
	passwordCost = bcrypt.DefaultCost
)

// 用ID获取用户
func GetUser(ID uint) (*User, error) {
	var user User
	result := DB.First(&user, ID)
	return &user, result.Error
}

// 设置密码
func (user *User) SetPassword(password string) error {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), passwordCost)
	if err != nil {
		return err
	}
	user.Password = string(bytes)
	return nil
}

// 校验密码
func (user *User) CheckPassword(password string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
	return err == nil
}

//根据用户id修改密码
func (user *User) ChangePassword(password string, Id uint) bool {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), passwordCost)
	if err != nil {
		return false
	}
	result := DB.Model(&user).Where("id = ?", Id).Update("password", string(bytes))
	return result.Error == nil
}

//根据用户邮箱修改密码（用于重置密码）
func (user *User) ChangePasswordByEmail(password string, email string) bool {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), passwordCost)
	fmt.Println(bytes, err)
	if err != nil {
		return false
	}
	result := DB.Model(&user).Where("email = ?", email).Update("password", string(bytes))
	fmt.Println(result)
	return result.Error == nil
}

//判断当前是否已经打卡
func IsDakaByUserId(uid string, time string) bool {
	res := DB.Where("uid = ? and data = ?", uid, time).Find(&UserDaka{})
	return res.RowsAffected > 0
}

//打卡
func DakaByUserId(uid string, time string, integral, isUseCode int) bool {
	info := UserDaka{Uid: uid, Data: time, Integral: integral, IsUseCode: isUseCode}
	res := DB.Create(&info)
	return res.RowsAffected > 0
}

//打卡天数结构体
type DakaDay struct {
	Num int
}

//计算连续打卡天数
func DakaRunningDays(uid string) DakaDay {
	var results DakaDay
	DB.Raw("SELECT count(1) as num FROM( "+
		" SELECT  date_sub( a.data, INTERVAL 1 DAY ) signDate, "+
		" ( @i := DATE_ADD( @i, INTERVAL - 1 DAY ) ) today "+
		"FROM"+
		" ( SELECT data FROM user_dakas WHERE uid = ? ORDER BY data DESC ) a"+
		" INNER JOIN ("+
		" SELECT @i := max( data ) AS signMax FROM user_dakas WHERE"+
		" uid = ? AND ( TO_DAYS( data ) = TO_DAYS( curdate()) OR TO_DAYS( data ) = TO_DAYS( DATE_ADD( curdate(), INTERVAL - 1 DAY ) ) ) ) b "+
		" WHERE b.signMax IS NOT NULL AND TO_DAYS( DATE_ADD( @i, INTERVAL - 1 DAY )) = TO_DAYS( date_sub( a.data, INTERVAL 1 DAY ) ) ) c",
		uid, uid).Scan(&results)
	return results
}

//获取总积分
func DakaIntegral(uid string) DakaDay {
	var result DakaDay
	DB.Raw("SELECT SUM(integral) - (SELECT COUNT(is_use_code)*10 FROM user_dakas WHERE uid = ? and is_use_code = '1' ) as num FROM user_dakas WHERE uid = ? ", uid, uid).Scan(&result)
	return result
}

//某年某月打卡数据结构体
type DakaDayInfo struct {
	Data string
}

//查询哪年哪月的签到数据
func DakaDayByMonth(uid, year, month string) []DakaDayInfo {
	var result []DakaDayInfo
	DB.Raw("select DATE_FORMAT(data,'%Y-%m-%d') as data from user_dakas where uid = ? and year(data)= ? and month(data)= ?  order by data", uid, year, month).Scan(&result)
	fmt.Println(result)
	return result
}
